<?php
/*
 * @Author: your name
 * @Date: 2020-11-17 10:39:34
 * @LastEditTime: 2021-01-15 10:50:06
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /special/application/adminapiv3/service/module_manage/netfilter/RuleLogService.php
 */
namespace app\adminapiv3\service\module_manage\netfilter;

use app\adminapiv3\model\HostInitialRuleModel;
use app\adminapiv3\model\NetfilterSafeRuleModel;
use app\adminapiv3\service\module_manage\netfilter\rule_log_service\RuleLogLinuxRuleService;
use app\adminapiv3\service\BaseService;
use app\adminapiv3\service\module_manage\netfilter\rule_log_service\RuleLogWindows2008RuleService;
use app\common\exception\CustomException;
use app\common\definition\netfilter\FirewallRuleDefinition;
use app\common\database\AutoIncreMentService;
use app\common\definition\HostDefinition;
use think\Db;
use think\Exception;

class RuleLogService extends BaseService
{
    
    /**
     * @name: 日志列表
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2020-11-17 10:41:04
     */
    public function list ($input)
    {
        $return = Db::name('netfilter_firewall_rule_log')->where($input)->where('status', FirewallRuleDefinition::ARCHIVED_LOG_STATUS)->order('id', 'DESC')->paginate()->toArray();

        return $return;
    }

    /**
     * @name: 规则回滚
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2020-11-17 10:40:53
     */
    public function reset ($input)
    {
        $return = Db::name('netfilter_firewall_rule_log')->where($input)->find();
        $os = $this->getHost('os', 'string');

        //添加用户操作日志
        global $logArray;
        $host_name_s = $this->getHost('name', 'string');
        $logArray = array(
            'content' => '防火墙规则回滚',
            'new_info' => '主机:' . $host_name_s . '回滚' . $input['signature_code'] .'版本'
        );
        
        if (empty($return))
        {
            throw new CustomException('未找到指定版本,请确认输入信息!!', 422);
        }

        switch ($return['type'])
        {
            case FirewallRuleDefinition::ERROR_RULE_GROUP :
                throw new CustomException('该版本存在断网可能,禁止回滚', 422);
            break;
            default :
                $this->ruleGroupReset($return['preview_content'], $return['back_content'], $input['host_id']);
        }
    }

    /**
     * @name: 详情
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2020-11-18 11:02:37
     */
    public function info ($input)
    {
        $data = Db::name('netfilter_firewall_rule_log')->field('preview_content,back_content,type')->where($input)->find();

        if (empty($data))
        {
            throw new CustomException('未找到指定版本,请确认输入信息!!', 422);
        }
        
        if ($data['type'] == FirewallRuleDefinition::INIT_RULE_GROUP)
        {
            $data['preview_content'] = '[]';
        }

        $preview_content = json_decode($data['preview_content'], true);

        $return['back_content'] = json_decode($data['back_content'], true);
        $return['preview_content'] = RulePreviewService::addShowName($preview_content);
        
        return $return;
    }

    /**
     * @name: 删除
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2020-11-18 11:27:39
     */
    public function delete ($input)
    {
        
        //添加用户操作日志
        global $logArray;
        $host_name_s = $this->getHost('name', 'string');
        $logArray = array(
            'content' => '防火墙规则版本删除',
            'new_info' => '主机:' . $host_name_s . '删除' . $input['signature_code'] .'版本'
        );

        try {
            Db::name('netfilter_firewall_rule_log')->where($input)->delete();
        } catch (\Exception $e)
        {
            throw new CustomException('未找到指定版本,请确认输入信息!!', 422);
        }
    }

    /**
     * @name: 获取回滚操作需要的数据
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2020-12-11 15:37:56
     */
    public function getResetOperationData (&$preview_content, &$source_a, &$handle_rule_data, $os)
    {
        //获取主机规则表自增id
        $auto_incre_id = AutoIncreMentService::getTableAutoId('host_rule');
        //循环处理预览内容
        foreach ($preview_content as $k => $v)
        {
            if($v['source']== FirewallRuleDefinition::FIREWALL_LOG_RULE_SOURCE)
            {
                unset($preview_content[$k]);
                continue;
            }
            
            if ($v['source'] == FirewallRuleDefinition::HANDLE_RULE_SOURCE)
            {
                if($os === HostDefinition::WINDOWS_OPERATION_SYSTEM)
                {
                    $RuleService = new RuleLogWindows2008RuleService($v['host_id'], $v['content']);
                }
                else
                {
                    $RuleService = new RuleLogLinuxRuleService($v['host_id'], $v['content']);
                    $RuleService->scope = $v['region'];
                }
                $RuleService->setData();
                $preview_content[$k]['rule_id'] = $fid = $auto_incre_id ++;
                
                $data = $RuleService->getData($fid, '回滚规则-'.time());
                $handle_rule_data = array_merge($handle_rule_data, $data);
            }
            else
            {
                $source_a[$v['source']][] = [
                    'id' => $v['rule_id'],
                    'status' => FirewallRuleDefinition::RULE_ENABLE
                ];
            }
        }
    }

    /**
     * @name: 回滚规则数据库操作
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2020-12-11 15:49:11
     */
    public function resetRuleDatabaseOperation ($host_id, $handle_rule_data, $source_a, $preview_content)
    {
        Db::startTrans();
        try {
            $HostInitialRuleModel = new HostInitialRuleModel();
            $NetfilterSafeRuleModel = new NetfilterSafeRuleModel();
            //清空主机用户自定义规则
            Db::name('host_rule')->where('host_id', $host_id)->delete();
            //清空主机防火墙预览规则
            Db::name('netfilter_firewall_rule')->where('host_id', $host_id)->delete();
            //重置所有原始规则状态
            $HostInitialRuleModel->where('host_id', $host_id)->update(['status' => FirewallRuleDefinition::RULE_DISABLE]);
            //重置所有通信规则状态(安全规则)
            $NetfilterSafeRuleModel->where('host_id', $host_id)->update(['status' => FirewallRuleDefinition::RULE_DISABLE]);
            //重新添加用户自定义规则数据
            Db::name('host_rule')->insertAll($handle_rule_data);
            //重置所有原始规则启用状态
            $origin_rule = FirewallRuleDefinition::ORIGIN_RULE_SOURCE;
            if(isset($source_a[$origin_rule]))
            {
                $HostInitialRuleModel->saveAll($source_a[$origin_rule]);
            }

            //重置所有通信规则启用状态
            $connect_rule = FirewallRuleDefinition::CONNECT_RULE_SOURCE;
            if(isset($source_a[$connect_rule]))
            {
                $NetfilterSafeRuleModel->saveAll($source_a[$connect_rule]);
            }
            //添加预览规则
            Db::name('netfilter_firewall_rule')->insertAll($preview_content);

            Db::commit();
        } catch (Exception $e)
        {
            Db::rollback();
            throw new CustomException('插入规则失败:'.$e->getMessage(), 302);
        }
    }

    /**
     * @name: 正常规则组回滚
     * @Param: 
     * @Description: 
     * @Author: foo
     * @Date: 2021-01-15 10:12:25
     */
    private function ruleGroupReset (string $preview_content, int $host_id, int $os)
    {

        $preview_content_a = json_decode($preview_content, true);
        //定义数据源容器
        $source_a = [];
        //自定义规则数据容器
        $handle_rule_data = [];
        //获取回滚操作数据
        $this->getResetOperationData($preview_content_a, $source_a, $handle_rule_data, $os);
        //重置规则数据库操作
        $this->resetRuleDatabaseOperation($host_id, $handle_rule_data, $source_a, $preview_content_a);
    }
}